package view;

import entity.Bullet;
import entity.Position;
import message.MessageInfo;
import tool.ExecutorServiceTool;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 坦克可视化
 * @author lijiahao
 */
public class TankClientView extends JFrame implements KeyListener {

	/**  
	 * @Fields serialVersionUID :            TODO
	 */   

	private static final long serialVersionUID = 1L;
	public static final String TITLE = "Tank Game图形绘制页面";
	private boolean isStarter = false;
	private final List<TankView> tanks = new ArrayList<>();
	private final TankView mySelf = null;
	private final StartView starterUp = new StartView();
	private DrawingCloth drawing;

	private final static TankClientView WINDOW = new TankClientView();

	/**
	 * @author:       lijiahao
	 * @date:         [2019年3月22日] 下午3:01:31
	 * @Description:  [TODO] 获取窗口实例
	 * @param:        @return
	 */
	public static TankClientView getWINDOW() {
		return WINDOW;
	}

	public interface Screen {
		int WIDTH = 900;
		int HEIGHT = 750;
	}

	public TankClientView() {
		super();
		initFrame();
	}

	private void initFrame() {
		// 设置 窗口标题 和 窗口大小
		setTitle(TITLE);
		setSize(Screen.WIDTH, Screen.HEIGHT);
		// 设置窗口关闭按钮的默认操作(点击关闭时退出进程)
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

		// 把窗口位置设置到屏幕的中心
		setLocationRelativeTo(null);
		this.addKeyListener(this);
		drawing = new DrawingCloth(this);
		setContentPane(drawing);		
	}

	public void init(TankView view) {
		tanks.add(view);
		drawing.setTankView(view);
		drawing.init();
	}
	
	public TankView getMySelf() {
		return this.mySelf;
	}

	public void destroy(TankView view) {
		tanks.remove(view);
	}

	public void doDrawing(Graphics g) {
		for(TankView tank: tanks) {
			tank.draw(g);
		}
	}

	private class DrawingCloth extends JPanel {

		/**  
		 * @Fields serialVersionUID :            TODO
		 */   
		private static final long serialVersionUID = 1L;
		private TankClientView view = null;
		private TankView tank = null;
		private Graphics g = null;
		private MoveThread moveThread = null;
		private RepaintThread repaintThread = null;
		private final Byte signal = new Byte("1");

		public DrawingCloth(TankClientView view) {
			this.view = view;
			setBackground(Color.BLUE);
		}
		
		public void setTankView(TankView tank) {
			this.tank = tank;
		}
		

		//画布初始化
		/**
		 * 在发送启动指令后，画布才初始化
		 * @author:       lijiahao
		 * @date:         [2019年3月22日] 下午3:23:41
		 * @Description:  [TODO]
		 * @param:        
		 */
		public void init() {
			this.view.addKeyListener(new TankListenerKey(this.getTank()));
			this.view.addKeyListener(new BulletListenerKey(this));
			this.moveThread = new MoveThread(this,signal);
			this.repaintThread = new RepaintThread(this);
			ExecutorServiceTool.execute(this.moveThread);
			ExecutorServiceTool.execute(this.repaintThread);
		}

		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			if(this.g==null)
				this.g = g;
			doDrawing(g);
		}

		public TankView getTank() {
			return tank;
		}

		public void notifyRepaintThread() {
			if(!repaintThread.isDraw()) {
				synchronized (repaintThread) {
					repaintThread.notify();
				}
			}
		}

		private class BulletListenerKey implements KeyListener {

			private TankView tank = null;
			private DrawingCloth cloth = null;

			public BulletListenerKey(DrawingCloth cloth) {
				this.tank = cloth.tank;
				this.cloth = cloth;
			}

			@Override
			public void keyTyped(KeyEvent e) {

			}

			@Override
			public void keyPressed(KeyEvent e) {
				if(KeyEvent.VK_SPACE==e.getKeyCode()) {
					BulletView b = new BulletView(tank.getGunPosition());
					b.setDir(tank.getDirection());
					this.tank.addBullet(b);
					//开启射击线程
					ExecutorServiceTool.execute(new ShootThread(cloth,b));
				} 
			}

			@Override
			public void keyReleased(KeyEvent e) {

			}
		}

		private class TankListenerKey implements KeyListener {


			public TankListenerKey(TankView tank) {
			}

			@Override
			public void keyTyped(KeyEvent e) {

			}

			@Override
			public void keyPressed(KeyEvent e) {
				int code = e.getKeyCode();
				if(KeyEvent.VK_UP==code) {
					moveThread.add(e.getKeyCode());
				} else if(KeyEvent.VK_DOWN==code) {
					moveThread.add(e.getKeyCode());
				} else if(KeyEvent.VK_LEFT==code) {
					moveThread.add(e.getKeyCode());
				} else if(KeyEvent.VK_RIGHT==code) {
					moveThread.add(e.getKeyCode());
				} 
				moveThread.setPressDown();
				synchronized (moveThread) {
					moveThread.notify();
				}
			}

			@Override
			public void keyReleased(KeyEvent e) {
				moveThread.remove(e.getKeyCode());
				if(moveThread.nohandle())
					moveThread.setPressUp();
			}

		}

		private class ShootThread implements Runnable {

			private DrawingCloth cloth = null;
			private Bullet bullet = null;

			public ShootThread(DrawingCloth cloth,Bullet bullet) {
				this.cloth = cloth;
				this.bullet = bullet;
			}

			@Override
			public void run() {
				while(true) {
					if(Position.isOverRound(bullet.getPosition())) {
						break;
					}
					//MoveGenerator.move(bullet.getPosition(), bullet.getDir(), bullet.getSpeed(), Bullet.class);
					cloth.notifyRepaintThread();
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}

		}

		private class RepaintThread implements Runnable {

			private DrawingCloth cloth = null;
			private boolean drawStatus = false;

			public RepaintThread(DrawingCloth cloth) {
				this.cloth = cloth;
			}

			@Override
			public void run() {
				while(true) {
					if(!drawStatus) {
						synchronized (this) {
							try {
								this.wait();
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
					cloth.repaint();
					drawStatus = false;
				}
			}

			public boolean isDraw() {
				return drawStatus;
			}

		}

		private class MoveThread implements Runnable {

			//上下左右操作序列
			private List<Integer> keys = new LinkedList<>();

			private TankView tank = null;
			private DrawingCloth cloth = null;
			private Byte signal = null;

			public MoveThread(DrawingCloth cloth,Byte signal) {
				this.tank = cloth.getTank();
				this.cloth = cloth;
				this.signal = signal;
			}

			@Override
			public void run() {
				while(true) {
					if(tank.isMove() && !keys.isEmpty() ) {
						int len = keys.size();
						int code = keys.get(len-1);
						MessageInfo info = null;
						if(KeyEvent.VK_UP==code) {
							tank.turnUp();
						} else if(KeyEvent.VK_DOWN==code) {
							tank.turnDown();
						} else if(KeyEvent.VK_LEFT==code) {
							tank.turnLeft();
						} else if(KeyEvent.VK_RIGHT==code) {
							tank.turnRight();
						} 
						tank.move();
						cloth.notifyRepaintThread();
					} else {
						synchronized (this) {
							try {
								this.wait();
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}

			public void setPressUp() {
				if(tank.isMove()) {
					tank.setMove(false);
				}
			}

			public void setPressDown() {
				if(!tank.isMove()) {
					tank.setMove(true);
				}
			}

			public void add(int keyCode) {
				synchronized (keys) {
					if(keys.size()==0 || keys.get(keys.size()-1)!=keyCode)
						keys.add(keyCode);
				}
			}

			public void remove(int keyCode) {
				if(keys!=null)
					synchronized (keys) {
						keys.remove(Integer.valueOf(keyCode));
					}
				if(keys==null)
					setPressUp();
			}	

			public boolean nohandle() {
				return keys.isEmpty();
			}

		}
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyPressed(KeyEvent e) {
		if(!isStarter) {
			if (e.getModifiers() == KeyEvent.CTRL_MASK && e.getKeyCode() == KeyEvent.VK_C) {
				starterUp.setVisible(true);
				starterUp.init();
				isStarter = true;
			}
		}
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub

	}
}
